<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/10/25
 * Time: 13:37
 */

namespace common\business\qywx;

use common\business\DbHandler;
use common\business\department\DepartmentApiHandler;
use common\business\EhrHelper;
use common\consts\CommonResources;
use common\consts\Consts;
use common\helpers\StringUtil;
use common\models\Department;
use common\models\kingdee\OrgAdmin;
use common\models\qywx\QywxDepartment;
use common\result\ActionResult;
use Yii;
use yii\db\Exception;

class QywxDepartmentService extends DbHandler
{
    /**
     * @var OrgAdmin
     */
    protected $_topOrg;

    /**
     * @var Department
     */
    protected $_topDepartment;

//    /**
//     * @var string
//     */
//    protected $_parentWxId;
//    public function setParentWxId($wxId){
//        $this->_parentWxId = $wxId;
//    }

    /**
     * @var string
     */
    protected $_department_number;
    public function setDepartmentNumber($department_number){
        $this->_department_number = $department_number;
    }

    /**
     * @param callback|null $writeBackHandler
     * @return ActionResult
     */
    public function sync($writeBackHandler = null) {
//        $this->_totalCount = OrgAdmin::find()->count();
        $totalResult = new ActionResult();
        $isSyncTopSuccess = $this->syncTopOrgAndTopQywxDepartment($totalResult, $writeBackHandler);
        if (!$isSyncTopSuccess){
            return new ActionResult(false, CommonResources::ACTION_FAIL_MSG('Sync', 'Department', $this->getErrorsMessage()));
        }
        $this->syncChildrenWithParentDepartment($this->_topOrg, $this->_topDepartment, $totalResult, $writeBackHandler);
        return $totalResult;
    }

    /**
     * 需要找到最顶层Org，并且寻找企业微信是是否有这个节点，如果名字不一样要更新
     * @param $totalResult ActionResult
     * @param callback|null $writeBackHandler
     * @return bool
     */
    protected function syncTopOrgAndTopQywxDepartment($totalResult, $writeBackHandler = null){
        $topIsRoot = false;
        $apiHandler = new QywxDepartmentApiHandler();
        $deptApi = new DepartmentApiHandler();

        $isSkipped = false;

        if(!StringUtil::isNullOrWhiteSpace($this->_department_number)){
            $topOrg = OrgAdmin::findOne([
                'FNUMBER' => $this->_department_number,
            ]);
            $topIsRoot = false;
        }
        //        否则拿顶层节点
        else{
            $topOrg = OrgAdmin::findOne([
                'FPARENTID' => null,
            ]);
            $topIsRoot = true;
        }

        if (!$topOrg)
        {
            $this->addError('Find Top Org', 'Top Org Not Found');
            $totalResult->addSubResult(new ActionResult(false, $this->getErrorsMessage()));
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return false;
        }

        if ($topIsRoot){
            $topDepartment = Department::findOne([
                'name' => EhrHelper::getName4QywxDepartment($topOrg),
                'number' => $topOrg->FNUMBER,
                'parent_id' => null,
            ]);
        }
        else {
            $topDepartment = Department::findOne([
                'name' => EhrHelper::getName4QywxDepartment($topOrg),
                'number' => $topOrg->FNUMBER,
            ]);
        }

        if (!$topDepartment){
            $topDepartment = new Department([
                'name' =>  EhrHelper::getName4QywxDepartment($topOrg),
                'display_name' => $topOrg->FDISPLAYNAME_L2,
                'kd_id' => $topOrg->FID,
                'number' => $topOrg->FNUMBER,
                'hr_status' => Consts::SYNC_STATUS_FINISHED,
            ]);
//            企业微信号赋值
            $topDepartment->qywx_id = $topOrg->FCODE;

            $createResult = $deptApi->createDepartment($topDepartment);
            $totalResult->addSubResult(new ActionResult(false, $createResult->getMessage()));
            if (!$createResult->isSuccess){
                $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
                return false;
            }
        }

        if ($topDepartment->hr_status == Consts::SYNC_STATUS_SYNCHRONIZING) {
            $this->addError('Sync Top', 'Other Thread is Syncing this record now.');
            $totalResult->addSubResult(new ActionResult(false, $this->getErrorsMessage(), true));
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return false;
        }

        $topDepartment->hr_status = Consts::SYNC_STATUS_SYNCHRONIZING;

//        查找企业微信根节点
        if ($topIsRoot){
            $topQywxDepartment = QywxDepartment::findOne([
                'parent_wx_id' => 0
            ]);
        }
        else {
            //删掉名字不对的所有节点
            QywxDepartment::deleteAll(
                'number=:number and name<>:name',
                [
                    ':number' => $topDepartment->number,
                    ':name' => $topDepartment->name,
                ]
            );

            $topQywxDepartment = QywxDepartment::findOne([
                'name' => $topDepartment->name,
                'number' => $topDepartment->number,
            ]);
        }

        if (!$topQywxDepartment){
            $topQywxDepartment = new QywxDepartment();
            $topQywxDepartment->name = $topDepartment->name;
            $topQywxDepartment->number = $topDepartment->number;
//            企业微信号赋值
            $topQywxDepartment->wx_id = $topDepartment->qywx_id;
            if (!StringUtil::isNullOrWhiteSpace($topDepartment->parent_qywx_id)){
                $topQywxDepartment->parent_wx_id = $topDepartment->parent_qywx_id;
            }
            if ($topIsRoot){
                $topQywxDepartment->parent_wx_id = 0;
            }

            $createResult = $apiHandler->createOrUpdateQywxDepartment($topQywxDepartment);
            if (!$createResult->isSuccess){
                $this->addErrors($apiHandler->getErrors());
                $totalResult->addSubResult($createResult);
                $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
                return false;
            }
        }
        else {
            $topQywxDepartment->name = $topDepartment->name;
            $topQywxDepartment->number = $topDepartment->number;
            if (!StringUtil::isNullOrWhiteSpace($topDepartment->parent_qywx_id)){
                $topQywxDepartment->parent_wx_id = $topDepartment->parent_qywx_id;
            }
            if ($topIsRoot){
                $topQywxDepartment->parent_wx_id = 0;
            }

            $updateResult = $apiHandler->createOrUpdateQywxDepartment($topQywxDepartment, false);
            if (!$updateResult->isSuccess){
                $this->addErrors($apiHandler->getErrors());
                $totalResult->addSubResult($updateResult);
                $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
                return false;
            }
            if ($updateResult->isSkipped)
                $isSkipped = true;
        }

        $topDepartment->qywx_id = $topQywxDepartment->wx_id;
        $topDepartment->parent_qywx_id = $topQywxDepartment->parent_wx_id;
        $topDepartment->order = $topQywxDepartment->order;

        $topDepartment->kd_id = $topOrg->FID;
        $topDepartment->display_name = $topOrg->FDISPLAYNAME_L2;
        $topDepartment->number = $topOrg->FNUMBER;
        $topDepartment->hr_status = Consts::SYNC_STATUS_FINISHED;

        $updateResult = (new DepartmentApiHandler())->updateDepartment($topDepartment);
        if (!$updateResult->isSuccess){
            $totalResult->addSubResult($updateResult);
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return false;
        }
        if ($updateResult->isSkipped)
            $isSkipped = true;

        $this->_topOrg =  $topOrg;
        $this->_topDepartment = $topDepartment;
        $totalResult->addSubResult(new ActionResult(true, CommonResources::ACTION_SUCCESS_MSG('Sync Top', 'QywxDepartment'), $isSkipped));
        $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
        return true;
    }

    /**
     * @param $parentOrg OrgAdmin
     * @param $parentDepartment Department
     * @param $totalResult ActionResult
     * @param callback|null $writeBackHandler
     */
    protected function syncChildrenWithParentDepartment($parentOrg, $parentDepartment, $totalResult, $writeBackHandler = null){
        $childrenOrgs = OrgAdmin::findAll([
            'FPARENTID' => $parentOrg->FID,
        ]);
        if (sizeof($childrenOrgs) == 0){
            return;
        }
        foreach ($childrenOrgs as $childOrg){
            $childDepartment = $this->syncSingleOrgWithParent($childOrg, $parentDepartment, $totalResult, $writeBackHandler);
            if ($childDepartment){
                $this->syncChildrenWithParentDepartment($childOrg, $childDepartment, $totalResult, $writeBackHandler);
            }
        }
    }

    /**
     * @param $org OrgAdmin
     * @param $parentDepartment Department
     * @param $totalResult ActionResult
     * @param callback|null $writeBackHandler
     * @return Department
     */
    protected function syncSingleOrgWithParent($org, $parentDepartment, $totalResult, $writeBackHandler = null){
        $isSkipped = false;
        $apiHandler = new QywxDepartmentApiHandler();
        $deptApi = new DepartmentApiHandler();

        $departmentInDb = Department::findOne([
            'name' => EhrHelper::getName4QywxDepartment($org),
            'parent_number' => $parentDepartment->number,
        ]);

        if (!$departmentInDb){
            $newDepartment = new Department([
                'name' =>  EhrHelper::getName4QywxDepartment($org),
                'display_name' => $org->FDISPLAYNAME_L2,
                'parent_id' => $parentDepartment->id,
                'parent_number' => $parentDepartment->parent_number,
                'kd_id' => $org->FID,
                'number' => $org->FNUMBER,
                'parent_kd_id' => $parentDepartment->kd_id,
                'parent_qywx_id' => $parentDepartment->qywx_id,
                'hr_status' => Consts::SYNC_STATUS_FINISHED,
            ]);
//            企业微信号赋值
            $newDepartment->qywx_id = $org->FCODE;
            $newDepartment->parent_qywx_id = $parentDepartment->qywx_id;

            $createResult = $deptApi->createDepartment($newDepartment);
            $totalResult->addSubResult(new ActionResult(false, $createResult->getMessage()));
            if (!$createResult->isSuccess){
                $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
                return null;
            }

            $departmentInDb = Department::findOne([
                'number' => $org->FNUMBER
            ]);
//            $departmentInDb = $newDepartment;
        }

        if ($departmentInDb->hr_status == Consts::SYNC_STATUS_SYNCHRONIZING) {
            $this->addError('Sync Top', 'Other Thread is Syncing this record now.');
            $totalResult->addSubResult(new ActionResult(false, $this->getErrorsMessage(), true));
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return null;
        }

        $departmentInDb->hr_status = Consts::SYNC_STATUS_SYNCHRONIZING;
        $departmentInDb->parent_number = $parentDepartment->number;
        $departmentInDb->parent_id = $parentDepartment->id;
        $departmentInDb->parent_qywx_id = $parentDepartment->qywx_id;

        //删掉名字不对的所有节点
        QywxDepartment::deleteAll(
            'number=:number and name<>:name',
            [
                ':number' => $departmentInDb->number,
                ':name' => $departmentInDb->name,
            ]
        );
        //查找企业微信相关节点
        $qywxDepartment = QywxDepartment::findOne([
            'name' => $departmentInDb->name,
            'number' => $departmentInDb->number,
        ]);
//        找不到就新建
        if (!$qywxDepartment){
            $qywxDepartment = new QywxDepartment();
            $qywxDepartment->name = $departmentInDb->name;
            $qywxDepartment->number = $departmentInDb->number;
            $qywxDepartment->parent_wx_id = $departmentInDb->parent_qywx_id;
//            企业微信号赋值
            $qywxDepartment->wx_id = $departmentInDb->qywx_id;

            $createResult = $apiHandler->createOrUpdateQywxDepartment($qywxDepartment);
            if (!$createResult->isSuccess){
                $this->addErrors($apiHandler->getErrors());
                $totalResult->addSubResult($createResult);
                $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
                return null;
            }

            $departmentInDb->qywx_id = $qywxDepartment->wx_id;
            $departmentInDb->parent_qywx_id = $qywxDepartment->parent_wx_id;
        }
        else {
            $qywxDepartment->name = $departmentInDb->name;
            $qywxDepartment->number = $departmentInDb->number;
            $qywxDepartment->parent_wx_id = $parentDepartment->qywx_id;

            $updateResult = $apiHandler->createOrUpdateQywxDepartment($qywxDepartment, false);
            if (!$updateResult->isSuccess){
                $this->addErrors($apiHandler->getErrors());
                $totalResult->addSubResult($updateResult);
                $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
                return null;
            }
        }

        $departmentInDb->qywx_id = $qywxDepartment->wx_id;
        $departmentInDb->order = $qywxDepartment->order;

        $departmentInDb->kd_id = $org->FID;
        $departmentInDb->parent_kd_id = $org->FPARENTID;
        $departmentInDb->number = $org->FNUMBER;
        $departmentInDb->display_name = $org->FDISPLAYNAME_L2;
        $departmentInDb->hr_status = Consts::SYNC_STATUS_FINISHED;

        $updateResult = $deptApi->updateDepartment($departmentInDb);
        if (!$updateResult->isSuccess){
            $totalResult->addSubResult($updateResult);
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return null;
        }
        if ($updateResult->isSkipped)
            $isSkipped = true;

        $totalResult->addSubResult(new ActionResult(true, CommonResources::ACTION_SUCCESS_MSG('Sync Single', 'Department'), $isSkipped));
        $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
        return $departmentInDb;
    }

    /**
     * @param string|null $qywx_id
     * @param callback|null $writeBackHandler
     * @return ActionResult
     */
    public function cascadeDelete($qywx_id = null, $writeBackHandler = null){
        if (StringUtil::isNullOrWhiteSpace($qywx_id)){
            $qywx_id = 1;
        }
        $topDepartment = QywxDepartment::findOne([
            'wx_id' => $qywx_id
        ]);

        $allChildrenCount = sizeof(QywxDepartment::findAll([
            'parent_wx_id' => $topDepartment->wx_id
        ]));
        $this->_totalCount = $allChildrenCount + 1;

        $totalResult = new ActionResult();
        $deleteSuccess = $this->deleteSelfAndChildren($topDepartment, $totalResult, $writeBackHandler);
        return $totalResult;
    }


    /**
     * @param $selfDepartment QywxDepartment
     * @param callback|null $writeBackHandler
     * @param $totalResult ActionResult
     * @return bool
     */
    protected function deleteSelfAndChildren($selfDepartment, $totalResult, $writeBackHandler = null){
        $allChildren = QywxDepartment::findAll([
            'parent_wx_id' => $selfDepartment->wx_id
        ]);

        foreach ($allChildren as $childDepartment){
            $delChildSuccess = $this->deleteSelfAndChildren($childDepartment, $totalResult);
        }

        $apiHandler = new QywxDepartmentApiHandler();
        $delSelfSuccess = $apiHandler->delete($selfDepartment->wx_id);
        if (!$delSelfSuccess){
            $this->addErrors($apiHandler->getErrors());
            $totalResult->addSubResult(new ActionResult(false));
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return false;
        }
        else {
            if (!$selfDepartment->delete()){
                $this->addErrors($selfDepartment->getErrors());
            }
            $totalResult->addSubResult(new ActionResult(true));
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return true;
        }
    }
}